package com.caffeinatedbliss.nanowrimo;

import java.awt.*;
import java.awt.image.BufferedImage;

public class Graph implements DynamicImageGenerator {
  private static final int CURVE_RADIUS = 8;
  public static final int WIDTH = 140;
  public static final int HEIGHT = 204;

  public static final Color LIGHTEST_GREY = new Color(0xf0, 0xf0, 0xf0);
  public static final Color NOT_SO_LIGHTEST_GREY = new Color(0xbb, 0xbb, 0xdd);
  private static final GradientPaint GRADIENT = new GradientPaint(CURVE_RADIUS, CURVE_RADIUS,
    LIGHTEST_GREY, 2 * CURVE_RADIUS, CURVE_RADIUS * 7, NOT_SO_LIGHTEST_GREY, false);

  public static final Color GREY_BORDER = new Color(0xbb, 0xbb, 0xbb);
  public static final Color DK_GREY_BORDER = new Color(0x99, 0x99, 0x99);
  private static final GradientPaint OUTSIDE_GRADIENT = new GradientPaint(CURVE_RADIUS, CURVE_RADIUS,
    GREY_BORDER, 2 * CURVE_RADIUS, CURVE_RADIUS * 7, DK_GREY_BORDER, false);

  public static final Color GRAPH_BACKGROUND = new Color(0xee, 0xee, 0xee);
  public static final Color GREEN_INK = new Color(0x00, 0xcc, 0x00);

  private BufferedImage graphImage;
  private static final Font TEXT_FONT = new Font("dialog", Font.BOLD, 11);
  private NanowrimoComputer computer;

  public Graph(String history, int goal) {
    computer = new NanowrimoComputer(history, goal);
    init();
  }

  public Graph(int[] amounts, int goal) {
    computer = new NanowrimoComputer(amounts, goal);
    init();
  }

  private void init() {
    graphImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = (Graphics2D) graphImage.getGraphics();

    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    drawFilledRectangleWithCurvedCorners(g);
    drawWordCount(g);
    drawDaysLeft(g);

    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
    drawPercentCompleteBar(g);
    drawDetailedBarChart(g);

    g.dispose();
    computer = null;
  }

  private void drawDetailedBarChart(Graphics2D g) {
    int[] historyCounts = computer.getHistoryCounts();
    int[] expectedDayAmount = computer.getExpectedPerDayAmount();
    int maxAmount = computer.getMaxAmount();
    double percentComplete = computer.getPercentComplete();
    int daysLeft = computer.getDaysLeftNaNoWriMo();
    boolean started = (daysLeft != 30 || percentComplete != 0.0);

    g.setColor(GREY_BORDER);
    g.drawRect(7, 43, WIDTH - 15, 152);
    g.setColor(GRAPH_BACKGROUND);
    g.fillRect(8, 44, WIDTH - 16, 151);
    for (int i = 0; i < expectedDayAmount.length; i++) {
      int written = 0;
      boolean useRed = false;
      if (started && i < historyCounts.length) {
        written = historyCounts[i];
        useRed = true;
      }

      int greenWidth = (int) ((WIDTH - 18.0) / (double) maxAmount * written);
      int greyWidth = (int) ((WIDTH - 18.0) / (double) maxAmount * expectedDayAmount[i]);

      if (greyWidth > greenWidth) {
        g.setColor((useRed) ? Color.RED : Color.GRAY);
        g.fillRect(9, 25 + 20 + (i * 5), greyWidth, 4);
        g.setColor(GREEN_INK);
        g.fillRect(9, 25 + 20 + (i * 5), greenWidth, 4);
      } else {
        g.setColor(GREEN_INK);
        g.fillRect(9, 25 + 20 + (i * 5), greenWidth, 4);
        g.setColor(Color.LIGHT_GRAY);
        g.fillRect(9, 25 + 20 + (i * 5), greyWidth, 4);
      }
    }
  }

  private void drawDaysLeft(Graphics2D g) {
    int daysLeftNaNoWriMo = computer.getDaysLeftNaNoWriMo();
    g.setColor(Color.black);
    String dayCount = daysLeftNaNoWriMo + " Day" + ((daysLeftNaNoWriMo != 1) ? "s" : "") + " left";
    drawCenteredText(g, TEXT_FONT, dayCount, 25);
  }

  private void drawPercentCompleteBar(Graphics2D g) {
    double percentComplete = computer.getPercentComplete();
    int green = (int) (1 + (WIDTH - 15) * percentComplete / 100.0);
    g.setColor(GREY_BORDER);
    g.drawRect(5, 15, WIDTH - 11, 10);
    g.setColor(GRAPH_BACKGROUND);
    g.fillRect(6, 16, WIDTH - 13, 9);
    g.setColor(GREEN_INK);
    g.fillRect(7, 17, green, 7);
  }

  private void drawWordCount(Graphics2D g) {
    int current = computer.getCurrent();
    g.setColor(Color.black);
    drawCenteredText(g, TEXT_FONT, current + " words", -3);
  }

  private void drawCenteredText(Graphics g, Font textFont, String aTextString, int yPos) {
    g.setFont(textFont);
    FontMetrics fm = g.getFontMetrics(textFont);
    int ascent = fm.getAscent();
    int descent = fm.getDescent();
    int totalLineHeght = ascent + descent;
    int wordWidth = fm.stringWidth(aTextString);
    int leftEdge = (WIDTH - wordWidth) / 2;
    g.drawString(aTextString, leftEdge, yPos + totalLineHeght);
  }

  private void drawFilledRectangleWithCurvedCorners(Graphics2D g) {
    g.setPaint(GRADIENT);
    g.fillRoundRect(0, 0, WIDTH - 1, HEIGHT - 1, 2 * CURVE_RADIUS, 2 * CURVE_RADIUS);

    g.setPaint(OUTSIDE_GRADIENT);
    g.drawRoundRect(0, 0, WIDTH - 1, HEIGHT - 1, 2 * CURVE_RADIUS, 2 * CURVE_RADIUS);
  }

  public BufferedImage getGraphImage() {
    return graphImage;
  }
}
